// client.cpp
#define _WIN32_DCOM
#include <iostream.h>
#include <stdio.h>
#include <conio.h>
#include "Component B\component.h"

void display_proxy_info(IUnknown* pUnknown)
{
	DWORD AuthnSvc;
	DWORD AuthzSvc;
	OLECHAR* ServerPrincName;
	DWORD AuthnLevel;
	DWORD ImpLevel;
	RPC_AUTH_IDENTITY_HANDLE pAuthInfo;
	DWORD Capabilities;

	HRESULT hr = CoQueryProxyBlanket(pUnknown, &AuthnSvc, &AuthzSvc, &ServerPrincName, &AuthnLevel, &ImpLevel, &pAuthInfo, &Capabilities);
	if(FAILED(hr))
		cout << "CoQueryProxyBlanket failed" << endl;

	cout << endl << "Proxy security blanket information follows:" << endl;

	switch(AuthnSvc)
	{
	case RPC_C_AUTHN_NONE:
		cout << "Authentication service is RPC_C_AUTHN_NONE." << endl;;
		break;
	case RPC_C_AUTHN_GSS_NEGOTIATE:
		cout << "Authentication service is RPC_C_AUTHN_GSS_NEGOTIATE." << endl;
		break;
	case RPC_C_AUTHN_GSS_KERBEROS:
		cout << "Authentication service is RPC_C_AUTHN_GSS_KERBEROS." << endl;
		break;
	case RPC_C_AUTHN_WINNT:
		cout << "Authentication service is RPC_C_AUTHN_WINNT." << endl;
		break;
	case RPC_C_AUTHN_DEFAULT:
		cout << "Authentication service is RPC_C_AUTHN_DEFAULT." << endl;
		break;
	}

	switch(AuthzSvc)
	{
	case RPC_C_AUTHZ_NONE:
		cout << "Authorization service is RPC_C_AUTHZ_NONE." << endl;
		break;
	case RPC_C_AUTHZ_NAME:
		cout << "Authorization service is RPC_C_AUTHZ_NAME." << endl;
		break;
	case RPC_C_AUTHZ_DCE:
		cout << "Authorization service is RPC_C_AUTHZ_DCE." << endl;
		break;
	case RPC_C_AUTHZ_DEFAULT:
		cout << "Authorization service is RPC_C_AUTHZ_DEFAULT." << endl;
		break;
	}

	wprintf(L"The current principal name is %s.\n", ServerPrincName);
	CoTaskMemFree(ServerPrincName);

	switch(AuthnLevel)
	{
	case RPC_C_AUTHN_LEVEL_DEFAULT:
		cout << "Authentication level is RPC_C_AUTHN_LEVEL_DEFAULT." << endl;
		break;
	case RPC_C_AUTHN_LEVEL_NONE:
		cout << "Authentication level is RPC_C_AUTHN_LEVEL_NONE." << endl;
		break;
	case RPC_C_AUTHN_LEVEL_CONNECT:
		cout << "Authentication level is RPC_C_AUTHN_LEVEL_CONNECT." << endl;
		break;
	case RPC_C_AUTHN_LEVEL_CALL:
		cout << "Authentication level is RPC_C_AUTHN_LEVEL_CALL." << endl;
		break;
	case RPC_C_AUTHN_LEVEL_PKT:
		cout << "Authentication level is RPC_C_AUTHN_LEVEL_PKT." << endl;
		break;
	case RPC_C_AUTHN_LEVEL_PKT_INTEGRITY:
		cout << "Authentication level is RPC_C_AUTHN_LEVEL_PKT_INTEGRITY." << endl;
		break;
	case RPC_C_AUTHN_LEVEL_PKT_PRIVACY:
		cout << "Authentication level is RPC_C_AUTHN_LEVEL_PKT_PRIVACY." << endl;
		break;
	}

	switch(ImpLevel)
	{
	case RPC_C_IMP_LEVEL_DEFAULT:
		cout << "Impersonation level is RPC_C_IMP_LEVEL_DEFAULT." << endl;
		break;
	case RPC_C_IMP_LEVEL_ANONYMOUS:
		cout << "Impersonation level is RPC_C_IMP_LEVEL_ANONYMOUS." << endl;
		break;
	case RPC_C_IMP_LEVEL_IDENTIFY:
		cout << "Impersonation level is RPC_C_IMP_LEVEL_IDENTIFY." << endl;
		break;
	case RPC_C_IMP_LEVEL_IMPERSONATE:
		cout << "Impersonation level is RPC_C_IMP_LEVEL_IMPERSONATE." << endl;
		break;
	case RPC_C_IMP_LEVEL_DELEGATE:
		cout << "Impersonation level is RPC_C_IMP_LEVEL_DELEGATE." << endl;
		break;
	}

//	wprintf(L"The client identity user name is %s.\n", ((SEC_WINNT_AUTH_IDENTITY_W*)pAuthInfo)->User);
//	wprintf(L"The client identity domain name is %s.\n", ((SEC_WINNT_AUTH_IDENTITY_W*)pAuthInfo)->Domain);
//	wprintf(L"The client identity password is %s.\n", ((SEC_WINNT_AUTH_IDENTITY_W*)pAuthInfo)->Password);

	if((Capabilities | EOAC_NONE) == 0)
		cout << "Capabilities include EOAC_NONE" << endl;
	if((Capabilities | EOAC_DEFAULT) == 0)
		cout << "Capabilities include EOAC_DEFAULT" << endl;
	if((Capabilities | EOAC_MUTUAL_AUTH) == 0)
		cout << "Capabilities include EOAC_MUTUAL_AUTH" << endl;
	if((Capabilities | EOAC_STATIC_CLOAKING) == 0)
		cout << "Capabilities include EOAC_STATIC_CLOAKING" << endl;
	if((Capabilities | EOAC_DYNAMIC_CLOAKING) == 0)
		cout << "Capabilities include EOAC_DYNAMIC_CLOAKING" << endl;
	if((Capabilities | EOAC_SECURE_REFS) == 0)
		cout << "Capabilities include EOAC_SECURE_REFS" << endl;
	if((Capabilities | EOAC_ACCESS_CONTROL) == 0)
		cout << "Capabilities include EOAC_ACCESS_CONTROL" << endl;
	if((Capabilities | EOAC_APPID) == 0)
		cout << "Capabilities include EOAC_APPID" << endl;
	if((Capabilities | EOAC_DISABLE_AAA) == 0)
		cout << "Capabilities include EOAC_DISABLE_AAA" << endl;

//	_getch();
}

void main()
{
	cout << "Client: Calling CoInitializeEx()" << endl;
	HRESULT hr = 0;

	hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
		
	IUnknown* pUnknown;
	ISum* pSum;

	SEC_WINNT_AUTH_IDENTITY_W identity;
	identity.User = L"A";
	identity.UserLength = wcslen(L"A");
	identity.Domain = L"GuysDomain";
	identity.DomainLength = wcslen(L"GuysDomain");
	identity.Password = L"A";
	identity.PasswordLength = wcslen(L"A");
	identity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

	SOLE_AUTHENTICATION_INFO info;
	info.dwAuthnSvc = RPC_C_AUTHN_GSS_KERBEROS;
	info.dwAuthzSvc = RPC_C_AUTHZ_NONE;
	info.pAuthInfo = &identity;
	
	SOLE_AUTHENTICATION_LIST list;
	list.cAuthInfo = 1;
	list.aAuthInfo = &info;

	hr = CoInitializeSecurity(0, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_DELEGATE, 
		&list, EOAC_NONE, NULL);
	if(FAILED(hr))
	{
		printf("CoInitializeSecurity Failed = %0x\n", hr);
		exit(0);
	}

	COAUTHIDENTITY AuthIdentity;
	AuthIdentity.User = L"A";
	AuthIdentity.UserLength = wcslen(L"A");
	AuthIdentity.Domain = L"GuysDomain";
	AuthIdentity.DomainLength = wcslen(L"GuysDomain");
	AuthIdentity.Password = L"A";
	AuthIdentity.PasswordLength = wcslen(L"A");
	AuthIdentity.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;

	COAUTHINFO AuthInfo;
	AuthInfo.dwAuthnSvc = RPC_C_AUTHN_GSS_KERBEROS;
	AuthInfo.dwAuthzSvc = RPC_C_AUTHZ_NONE;
	AuthInfo.pwszServerPrincName = L"GuysDomain\\Oyarsa"; // Must specify machine prinicipal here
	AuthInfo.dwAuthnLevel = RPC_C_AUTHN_LEVEL_CONNECT;
	AuthInfo.dwImpersonationLevel = RPC_C_IMP_LEVEL_DELEGATE; // Computer account must be marked "Computer is trusted for delegation"
	AuthInfo.pAuthIdentityData = &AuthIdentity;
	AuthInfo.dwCapabilities = EOAC_NONE;

	COSERVERINFO ServerInfo;
	ServerInfo.dwReserved1 = 0;
	ServerInfo.pwszName =  L"Oyarsa";
	ServerInfo.pAuthInfo = &AuthInfo;
	ServerInfo.dwReserved2 = 0;

	MULTI_QI qi;
	qi.pIID = &IID_IUnknown;
	qi.pItf = NULL;
	qi.hr = 0;

	cout << "Client: Calling CoCreateInstanceEx() " << endl;
	hr = CoCreateInstanceEx(CLSID_InsideCOM_B, NULL, CLSCTX_REMOTE_SERVER, &ServerInfo, 1, &qi);
	pUnknown = qi.pItf;

	if(FAILED(hr))
	{
		if(hr == E_ACCESSDENIED)
			printf("CoCreateInstance FAILED hr = E_ACCESSDENIED\n", hr);
		else
			printf("CoCreateInstance FAILED hr = %0x\n", hr);
		exit(0);
	}

//	display_proxy_info(pUnknown);
//	_getch();
//
//	hr = CoSetProxyBlanket(pUnknown, RPC_C_AUTHN_DEFAULT, RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL, // L"GuysDomain\\B", 
//		RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_DEFAULT, COLE_DEFAULT_AUTHINFO, EOAC_DEFAULT);
//	if(FAILED(hr))
//	{
//			printf("CoSetProxyBlanket 1 FAILED hr = %0x\n", hr);
//			exit(0);
//	}



	display_proxy_info(pUnknown);


	cout << "Client: Calling QueryInterface() for ISum on " << pUnknown << endl;
	hr = pUnknown->QueryInterface(IID_ISum, (void**)&pSum);
	if(FAILED(hr))
	{
		printf("QueryInterface for ISum FAILED %0x\n", hr);
		exit(0);
	}

	hr = CoSetProxyBlanket(pSum, RPC_C_AUTHN_GSS_KERBEROS, RPC_C_AUTHZ_DEFAULT, COLE_DEFAULT_PRINCIPAL, // L"GuysDomain\\B", 
		RPC_C_AUTHN_LEVEL_DEFAULT, RPC_C_IMP_LEVEL_DELEGATE, COLE_DEFAULT_AUTHINFO, EOAC_DEFAULT);
	if(FAILED(hr))
			printf("CoSetProxyBlanket 2 FAILED hr = %0x\n", hr);

	display_proxy_info(pSum);


	cout << "Client: Calling Release() for pUnknown" << endl;
	hr = pUnknown->Release();

	cout << "Client: pSum = " << pSum << endl;

	int sum;
	hr = pSum->Sum(4, 9, &sum);
	if(SUCCEEDED(hr))
		cout << "Client: Calling Sum() return value is " << sum << endl;
	if(FAILED(hr))
		printf("Sum failed %0x\n", hr);

	cout << "Client: Calling Release() for pSum" << endl;
	hr = pSum->Release();

	cout << "Client: Calling CoUninitialize()" << endl;
	CoUninitialize();
}